package service

import (
	"encoding/base64"
	"io/ioutil"
	"log"
	"strings"
	"time"

	"gitee.com/cheng470/openai/util"
	"github.com/google/uuid"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	tts "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tts/v20190823"
)

type TxTtsService struct {
	secretId  string
	secretKey string
}

func NewTxTtsService(secretId, secretKey string) *TxTtsService {
	return &TxTtsService{
		secretId:  secretId,
		secretKey: secretKey,
	}
}

func (t *TxTtsService) HandleText2Audio(text string, volume, speed, voiceType int, emotionCategory string, emotionIntensity int) string {
	credential := common.NewCredential(t.secretId, t.secretKey)

	// 实例化一个client选项，可选的，没有特殊需求可以跳过
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "tts.tencentcloudapi.com"
	// 实例化要请求产品的client对象,clientProfile是可选的
	client, _ := tts.NewClient(credential, "ap-guangzhou", cpf)

	// 实例化一个请求对象,每个接口都会对应一个request对象
	request := tts.NewTextToVoiceRequest()

	// 默认音频格式为 wav
	request.Text = common.StringPtr(text)
	request.SessionId = common.StringPtr(uuid.NewString())
	if volume > 0 {
		request.Volume = common.Float64Ptr(float64(volume))
	}
	if speed != 0 {
		request.Speed = common.Float64Ptr(float64(speed))
	}
	if voiceType != 0 {
		request.VoiceType = common.Int64Ptr(int64(voiceType))
	}
	if len(emotionCategory) > 0 {
		request.EmotionCategory = common.StringPtr(emotionCategory)
	}
	if emotionIntensity != 0 {
		request.EmotionIntensity = common.Int64Ptr(int64(emotionIntensity))
	}

	// 返回的resp是一个TextToVoiceResponse的实例，与请求对象对应
	s := time.Now()
	response, err := client.TextToVoice(request)
	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		log.Printf("An API error has returned: %s", err)
		return ""
	}
	if err != nil {
		panic(err)
	}
	log.Printf("请求：%s\n响应： %s\n耗时: %d毫秒\n", util.JsonEncode(request), util.JsonEncode(response), time.Now().UnixMilli()-s.UnixMilli())
	// 输出json格式的字符串回包
	base64Str := response.Response.Audio
	return t.SaveToFile(base64Str)
}

func (t *TxTtsService) SaveToFile(base64Str *string) string {
	decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(*base64Str))
	fileName := time.Now().Format(time.RFC3339) + ".wav"
	buf := make([]byte, 2)
	dst := ""
	for {
		n, err := decoder.Read(buf)
		if n == 0 || err != nil {
			break
		}
		dst += string(buf[:n])
	}
	err := ioutil.WriteFile("./upload/"+fileName, []byte(dst), 0755)
	if err != nil {
		log.Println(err)
	}
	return fileName
}

func (t *TxTtsService) HandleText2Audio2(text string, volume, speed, voiceType int, emotionCategory string, emotionIntensity int) (response *tts.TextToVoiceResponse, err error) {
	credential := common.NewCredential(t.secretId, t.secretKey)

	// 实例化一个client选项，可选的，没有特殊需求可以跳过
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "tts.tencentcloudapi.com"
	// 实例化要请求产品的client对象,clientProfile是可选的
	client, _ := tts.NewClient(credential, "ap-guangzhou", cpf)

	// 实例化一个请求对象,每个接口都会对应一个request对象
	request := tts.NewTextToVoiceRequest()

	// 默认音频格式为 wav
	if len(text) > 150 {
		text = text[0:150]
	}
	request.Text = common.StringPtr(text)
	request.SessionId = common.StringPtr(uuid.NewString())
	if volume > 0 {
		request.Volume = common.Float64Ptr(float64(volume))
	}
	if speed != 0 {
		request.Speed = common.Float64Ptr(float64(speed))
	}
	if voiceType != 0 {
		request.VoiceType = common.Int64Ptr(int64(voiceType))
	}
	if len(emotionCategory) > 0 {
		request.EmotionCategory = common.StringPtr(emotionCategory)
	}
	if emotionIntensity != 0 {
		request.EmotionIntensity = common.Int64Ptr(int64(emotionIntensity))
	}

	// 返回的resp是一个TextToVoiceResponse的实例，与请求对象对应
	s := time.Now()
	response, err = client.TextToVoice(request)
	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		log.Printf("An API error has returned: %s", err)
		return
	}
	log.Printf("请求：%s\n响应： %s\n耗时: %d毫秒\n", util.JsonEncode(request), util.JsonEncode(response), time.Now().UnixMilli()-s.UnixMilli())
	return
}
